/*  utils.h utils.cpp
    Written by Salil Deena
    24/05/09

    Several utility functions like string tokenizer
*/

#include <vector>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <math.h>
#include <sstream>
#include <unistd.h>

using namespace std;

void TrimSpaces( string& str)  
{  
     // Trim Both leading and trailing spaces  
     size_t startpos = str.find_first_not_of(" \t"); // Find the first character position after excluding leading blank spaces
     size_t endpos = str.find_last_not_of(" \t"); // Find the first character position from reverse af  
   
     // if all spaces or empty return an empty string  
     if(( string::npos == startpos ) || ( string::npos == endpos))  
     {  
         str = "";  
     }  
     else  
         str = str.substr( startpos, endpos-startpos+1 );  
   
     /* 
     // Code for  Trim Leading Spaces only 
     size_t startpos = str.find_first_not_of(" \t"); // Find the first character position after excluding leading blank spaces 
     if( string::npos != startpos ) 
         str = str.substr( startpos ); 
     */  
   
     /* 
     // Code for Trim trailing Spaces only 
     size_t endpos = str.find_last_not_of(" \t"); // Find the first character position from reverse af 
     if( string::npos != endpos ) 
         str = str.substr( 0, endpos+1 ); 
     */  
 }  

void Tokenize(const string& str, string& first_token, vector<string>& remaining_tokens, const string& delimiters = " ")
{
    string local_str = str;
    //cout << local_str << endl;	
       
    vector<string> tokens;	
    // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(local_str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = local_str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = local_str.find_first_of(delimiters, lastPos);
    }

    first_token = tokens[0];
      
    for (int k = 1;k < tokens.size(); k++)
    {	
	remaining_tokens.push_back (tokens[k]);
    }	

}

void TokenizeIntoTokensOnly(const string& str, vector<string>& tokens, const string& delimiters = " ")
{
    string local_str = str;
    //cout << local_str << endl;	
       
     // Skip delimiters at beginning.
    string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    string::size_type pos = str.find_first_of(delimiters, lastPos);

    while (string::npos != pos || string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(local_str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = local_str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = local_str.find_first_of(delimiters, lastPos);
    }
}

void unTokenize (string& str, vector<string>& tokens, const string& delimiters = " ")
{	
	str = "";	
	if (tokens.size() > 0)
	{
		for (int i = 0;i < tokens.size();i++)
		{
			str.append (tokens[i]);
			str.append (delimiters);
		}
	}
}

void TokenizeTokens (vector<string>& tokens, string& first_token, vector<string>& remaining_tokens)
{
    if (tokens.size() == 0)
    {
	cout << "Size of tokens is 0 " << endl;	
    }
		
    first_token = tokens[0];
      
    for (int k = 1;k < tokens.size(); k++)
    {	
	remaining_tokens.push_back (tokens[k]);
    }		
} 

string str_replace(const string search, const string replace, string subject)
{
    string buffer;
   
    int sealeng = search.length();
    int strleng = subject.length();

    if (sealeng==0)	
        return subject;//no change

    for(int i=0, j=0; i<strleng; j=0 )
    {
        while (i+j<strleng && j<sealeng && subject[i+j]==search[j])
            j++;
        if (j==sealeng)//found 'search'
        {
            buffer.append(replace);
            i+=sealeng;
        }
        else
        {
            buffer.append( &subject[i++], 1);
        }
    }
    subject = buffer;
    return subject;
}

void IntToString(int i, string & s)
{
    s = "";
    if (i == 0)
    {
        s = "0";
        return;
    }
    if (i < 0)
    {
        s += '-';
        i = -i;
    }
    int count = log10(i);
    while (count >= 0)
    {
        s += ('0' + i/pow(10.0, count));
        i -= static_cast<int>(i/pow(10.0,count)) * static_cast<int>(pow(10.0,count));
        count--;
    }
}

void DoubleToString(double d, string & s)
{
	// convert double b to string s
	std::ostringstream ss;
	ss << d;
	s = ss.str();
}

void parseActFile (string act_file, string &prePath, float &shape_var, float &texture_var, float &combined_var, bool &mode)
{
	string line;
	string field;
	vector<string> field_vals;
	string field_data;
	vector<string> unwanted_tokens;
	int line_number=1;

	ifstream myfile (act_file.c_str());
	if (myfile.is_open())
	{
		while (! myfile.eof() )
	  	{
			if (line_number == 6)
				break;

			getline (myfile,line);
	    		Tokenize(line, field, field_vals, "=");
			line = field_vals[0];	 
			Tokenize(line, field_data, unwanted_tokens, ";");
		
			if (line_number == 1)
			{
				prePath = field_data;
			}
			else if (line_number == 2)
			{				
				shape_var = atof (field_data.c_str());
			}
			else if (line_number == 3)
			{
				texture_var = atof (field_data.c_str());
			}
			else if (line_number == 4)
			{
				combined_var = atof (field_data.c_str());
			}
			else if (line_number == 5)
			{
				mode = atoi (field_data.c_str());
			}
			
			field_vals.clear();
			unwanted_tokens.clear();
			
			line_number++;	       
	  	}
	  	myfile.close();
	}

	else 
	{
		cout << "Unable to open the configuration file" << endl; 
		exit(1);
	}
}

// function to return the current working directory
// this is generally the application path
void GetCurrentPath(char* buffer)
{
	getcwd(buffer, 200);
}

void RemoveCarriageReturn(string &word)
{
	std::string::iterator e(word.end() - 1);

	if(*e == '\n')
		word.erase(e);
}
